package com.stone.scan;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * <p>Created with IntelliJ IDEA. </p>
 * <p>User: Stony </p>
 * <p>Date: 2016/7/1 </p>
 * <p>Time: 14:09 </p>
 * <p>Version: 1.0 </p>
 */
public class OptimizerScanner extends ClassPathBeanDefinitionScanner {
    private volatile boolean isInit = false;
    private final Object monitor = new Object();

    /**
     * 不加载默认的过滤器
     * @param registry
     */
    public OptimizerScanner(BeanDefinitionRegistry registry) {
        this(registry, false);
    }

    public OptimizerScanner(BeanDefinitionRegistry registry, boolean b) {
        super(registry, b);
        init();
    }

    public void init(){
        if(isInit){
            return;
        }
        setIncludeAnnotationConfig(true);
        addIncludeFilter(new AnnotationTypeFilter(Optimizer.class));
        addExcludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                String className = metadataReader.getClassMetadata().getClassName();
                return className.endsWith("package-info");
            }
        });
        synchronized (monitor) {
            isInit = true;
        }
    }

    /**
     * 多个以(,; )逗号和冒号分隔
     * @param basePackage
     * @return
     * @throws ClassNotFoundException
     */
    public List<Class> scanBeanClass(String basePackage) throws ClassNotFoundException {
        return scanBeanClass(StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }
    public List<Class> scanBeanClass(String... basePackages) throws ClassNotFoundException {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        ClassLoader beanClassLoader = OptimizerScanner.class.getClassLoader(); //ClassUtils.getDefaultClassLoader();
        List<Class> beanClass = new LinkedList<>();
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                beanClass.add(resolveClassName(candidate.getBeanClassName(), beanClassLoader));
            }
        }
        return beanClass;
    }

    protected Class<?> resolveClassName(String className, ClassLoader beanClassLoader) throws ClassNotFoundException {
        return ClassUtils.forName(className, beanClassLoader);
    }
}
